//
// Created by marcin on 5/11/15.
//

#include "tools.h"

namespace xmreg
{


    /**
     * Parse key string, e.g., a viewkey in a string
     * into crypto::secret_key or crypto::public_key
     * depending on the template argument.
     */
    template <typename T>
    bool
    parse_str_secret_key(const string& key_str, T& secret_key)
    {

        // hash and keys have same structure, so to parse string of
        // a key, e.g., a view key, we can first parse it into the hash
        // object using parse_hash256 function, and then copy the reslting
        // hash data into secret key.
        crypto::hash hash_;

        if(!parse_hash256(key_str, hash_))
        {
            cerr << "Cant parse a key (e.g. viewkey): " << key_str << endl;
            return false;
        }

        // crypto::hash and crypto::secret_key have basicly same
        // structure. They both keep they key/hash as c-style char array
        // of fixed size. Thus we can just copy data from hash
        // to key
        copy(begin(hash_.data), end(hash_.data), secret_key.data);

        return true;
    }

    /**
 * Parse monero address in a string form into
 * cryptonote::account_public_address object
 */
    bool
    parse_str_address(const string& address_str, account_public_address& address)
    {
        address_parse_info info;
        info.address = address;
        info.has_payment_id = false;
        info.is_subaddress = false;
        info.payment_id = null_hash8;

        if (!get_account_address_from_str(info, false, address_str))
        {
            cerr << "Error getting address: " << address_str << endl;
            return false;
        }

        return true;
    }


    /**
     * Return string representation of monero address
     */
    string
    print_address(const account_public_address& address)
    {
        return get_account_address_as_str(false, false, address);
    }

    // explicit instantiations of get template function
    template bool parse_str_secret_key<crypto::secret_key>(const string& key_str, crypto::secret_key& secret_key);
    template bool parse_str_secret_key<crypto::public_key>(const string& key_str, crypto::public_key& secret_key);

    ostream&
    operator<< (ostream& os, const account_public_address& addr)
    {
        os << "<" << get_account_address_as_str(false, false, addr) << ">";
        return os;
    }


    ostream&
    operator<< (ostream& os, const xmreg::secret_key16& sec16)
    {
        os << "<" << epee::string_tools::pod_to_hex(sec16)  << ">";
        return os;
    }

    /**
     * Performs keecak hash on the private key provided
     *
     */
    void
    keccak_hash(secret_key& prv, crypto::hash& result)
    {
        keccak(reinterpret_cast<uint8_t *>(&prv), sizeof(secret_key),
              (uint8_t *) &result, sizeof(secret_key));
    }


    /**
     * Converts crypto::hash into crypto::secret_key or crypto::public_key
     *
     * Both hash and secret have the same internal structure, i.e.,
     * they are both struct containing char[32]. Thus
     * we can use reinterperter_cast to cast hash into
     * corresponding key.
     */
    template <typename T>
    T get_key_from_hash(crypto::hash& in_hash)
    {
        T* key;
        key = reinterpret_cast<T*>(&in_hash);
        return *key;
    }

    // explicit instantiations of get_key_from_hash function
    template secret_key get_key_from_hash<secret_key>(crypto::hash& in_hash);
    template public_key get_key_from_hash<public_key>(crypto::hash& in_hash);


}
